package com.hmall.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.hmall.common.dto.PageDTO;
import com.hmall.common.pojo.Item;
import com.hmall.search.pojo.ItemDoc;
import com.hmall.search.pojo.Search;
import com.hmall.search.service.SearchService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private RestHighLevelClient client;

    /**
     * 首页数据条
     * @param search
     * @return
     */
    @Override
    public Map<String, List<String>> search(Search search) {
        //返回值对象
        HashMap<String,List<String>> map = new HashMap<>();

        ArrayList<String> brand = new ArrayList<>();

        ArrayList<String> category = new ArrayList<>();
        map.put("brand",brand);
        map.put("category",category);

        //构建 分页、查询源对象、查询条件
        SearchRequest Request = new SearchRequest();


        //查询源
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //条件查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //关键字用精确查找
        if (!StringUtils.isEmpty(search.getKey())){
            boolQuery.must(QueryBuilders.matchQuery("all",search.getKey()));
        }else {
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        //其他条件设置为过滤，不影响查询性能，不影响算分
        if (!StringUtils.isEmpty(search.getCategory())){
            boolQuery.filter(QueryBuilders.termQuery("category",search.getCategory()));
        }
        if (!StringUtils.isEmpty(search.getBrand())){
            boolQuery.filter(QueryBuilders.termQuery("brand",search.getBrand()));
        }

        if (search.getMaxPrice() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(search.getMaxPrice()*100));
        }
        if (search.getMinPrice() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(search.getMinPrice()*100));
        }
        //查询条件放入查询源
        searchSourceBuilder.query(boolQuery);
        //指定分页条件
        int from = (search.getPage()-1)*search.getSize();
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(search.getSize());

        //排序
        if (!StringUtils.isEmpty(search.getSortBy())){
            if (search.getSortBy().equals("price")){
                searchSourceBuilder.sort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
            }
            if (search.getSortBy().equals("sold")){
                searchSourceBuilder.sort(SortBuilders.fieldSort("sold").order(SortOrder.DESC));
            }
        }

        TermsAggregationBuilder builder = AggregationBuilders.terms("brandAgg").field("brand").size(96);
        searchSourceBuilder.aggregation(builder);
        TermsAggregationBuilder builder1 = AggregationBuilders.terms("categoryAgg").field("category").size(20);
        searchSourceBuilder.aggregation(builder1);
        searchSourceBuilder.size(0);

        Request.source(searchSourceBuilder);

        //结果解析
        try {
            SearchResponse response = client.search(Request, RequestOptions.DEFAULT);
            Aggregations aggregations = response.getAggregations();
            Terms brandaggs = aggregations.get("brandAgg");
            List<? extends Terms.Bucket> buckets = brandaggs.getBuckets();
            for (Terms.Bucket bucket : buckets) {
                String key = bucket.getKeyAsString();
                brand.add(key);
            }

            Terms categoryaggs = aggregations.get("categoryAgg");
            List<? extends Terms.Bucket> buckets1 = categoryaggs.getBuckets();
            for (Terms.Bucket bucket : buckets1) {
                String key = bucket.getKeyAsString();
                category.add(key);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        return map;

    }
    /**
     * 数据查询
     */
    @Override
    public PageDTO<ItemDoc> list(Search search) {
        //根据传入的关键字查询酒店
        SearchRequest Request = new SearchRequest("hm-mall");
        //构建查询源对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //构建查询条件
        QueryBuilder queryBuilder = null;

        //判断关键字是否为空
        if (StringUtils.isEmpty(search.getKey())){
            //为空查询所有
            queryBuilder = QueryBuilders.matchAllQuery();
        }else {
            queryBuilder = QueryBuilders.matchQuery("all",search.getKey());


            HighlightBuilder highlightBuilder = new HighlightBuilder();
            //查询和高亮不一致需要标注！！
            highlightBuilder.requireFieldMatch(false);

            highlightBuilder.field("name");
            highlightBuilder.preTags("<em>");
            highlightBuilder.postTags("</em>");
            sourceBuilder.highlighter(highlightBuilder);
        }
        BoolQueryBuilder boolQuery = new BoolQueryBuilder();
        boolQuery.must(queryBuilder);

        //其他条件设置为过滤，不影响查询性能，不影响算分
        if (!StringUtils.isEmpty(search.getCategory())){
            boolQuery.filter(QueryBuilders.termQuery("category",search.getCategory()));
        }
        if (!StringUtils.isEmpty(search.getBrand())){
            boolQuery.filter(QueryBuilders.termQuery("brand",search.getBrand()));
        }

        if (search.getMaxPrice() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(search.getMaxPrice()*100));
        }
        if (search.getMinPrice() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(search.getMinPrice()*100));
        }
        //得加钱
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(
                boolQuery,new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder
                                (QueryBuilders.termQuery("isAD",true),
                                ScoreFunctionBuilders.weightFactorFunction(10))
                }
        );
        sourceBuilder.query(functionScoreQueryBuilder);
        //开启分页查询
        int from = (search.getPage() -1)*search.getSize();
        sourceBuilder.from(from);
        sourceBuilder.size(search.getSize());

        sourceBuilder.sort("_score",SortOrder.DESC);
        if (!StringUtils.isEmpty(search.getSortBy())){
            if (search.getSortBy().equals("price")){
                sourceBuilder.sort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
            }
            if (search.getSortBy().equals("sold")){
                sourceBuilder.sort(SortBuilders.fieldSort("sold").order(SortOrder.DESC));
            }
        }
        Request.source(sourceBuilder);
        PageDTO<ItemDoc> pageDTO = new PageDTO<>();
        List<ItemDoc> list = new ArrayList<>();
        try {
            SearchResponse response = client.search(Request, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            long value = hits.getTotalHits().value;
            pageDTO.setTotal(value);
            SearchHit[] hits1 = hits.getHits();
            for (SearchHit hit : hits1) {
                String json = hit.getSourceAsString();
                ItemDoc itemDoc = JSON.parseObject(json, ItemDoc.class);
                if (!StringUtils.isEmpty(hit.getHighlightFields().get("name"))){
                    String name = hit.getHighlightFields().get("name").fragments()[0].toString();
                    itemDoc.setName(name);
                }
                list.add(itemDoc);
                pageDTO.setList(list);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pageDTO;
    }

}
